package org.witsoft.dtx.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.witsoft.dtx.domain.BranchStatus;
import org.witsoft.dtx.domain.GlobalStatus;
import org.witsoft.dtx.domain.GlobalTransaction;
import org.witsoft.dtx.service.GlobalTransactionService;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

/**
 * @author XiaoQing Lin
 * @date 2020-09-21 10:36
 */
public class GlobalTransactionServiceImpl implements GlobalTransactionService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void add(GlobalTransaction entity) {
        String sql = "INSERT INTO dtx_global(id,timeout,status,create_time,update_time) " +
                "VALUES(?,?,?,?,?)";
        entity.setStatus(GlobalStatus.PREPARE);
        entity.setCreateTime(new Timestamp(System.currentTimeMillis()));
        entity.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        jdbcTemplate.update(sql,
                entity.getId(),
                entity.getTimeout(),
                entity.getStatus().getValue(),
                entity.getCreateTime(),
                entity.getUpdateTime()
        );
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void updateStatus(GlobalTransaction entity) {
        String sql = "UPDATE dtx_global SET status=?, update_time=? WHERE id=?";
        jdbcTemplate.update(sql,
                entity.getStatus().getValue(),
                new Date(),
                entity.getId()
        );
    }

    @Override
    public GlobalTransaction findById(String id) {
        String sql = "SELECT id,timeout,status,create_time,update_time,NOW() FROM dtx_global WHERE id=?";
        return jdbcTemplate.queryForObject(sql, new Object[]{id},new RowMapper<GlobalTransaction>() {
                    @Override
                    public GlobalTransaction mapRow(ResultSet rs, int i) throws SQLException {
                        return innerMapRow(rs);
                    }
                }
        );
    }

    @Override
    public void tryUpdateToCompleted(String id , GlobalStatus status) {
        BranchStatus branchStatus;
        if(status == GlobalStatus.CANCELED) {
            branchStatus = BranchStatus.CANCELED;
        }else{
            branchStatus = BranchStatus.CONFIRMED;
        }
        String sql = "select count(1), ifnull(sum(case when status=? then 1 else 0 end),0) from dtx_branch where gid=?";
        SqlRowSet rs = jdbcTemplate.queryForRowSet(sql, branchStatus.getValue(), id);
        if(!rs.next()){
            return;
        }
        int total = rs.getInt(1);
        int count = rs.getInt(2);
        boolean completed = count >= total;
        if(!completed){
            return;
        }
        GlobalTransaction entity = findById(id);
        entity.setStatus(status);
        this.updateStatus(entity);
    }


    private GlobalTransaction innerMapRow(ResultSet rs) throws SQLException {
        String id = rs.getString("id");
        GlobalTransaction entity = new GlobalTransaction(id);
        entity.setTimeout(rs.getInt("timeout"));
        entity.setStatus(GlobalStatus.of(rs.getInt("status")));
        entity.setCreateTime(rs.getTimestamp("create_time"));
        entity.setUpdateTime(rs.getTimestamp("update_time"));
        return entity;
    }
}
